import { ipcMain, BrowserWindow } from 'electron'
import { IPC_CHANNELS } from 'shared/ipcChannels'
import fs from 'node:fs'
import path from 'node:path'
import { spawn } from 'node:child_process'
// @ts-ignore
import ffmpegInstaller from '@ffmpeg-installer/ffmpeg'

const FFMPEG_PATH = ffmpegInstaller.path

interface SplitAudioConfig {
  inputPath: string
  outputFolder: string
  splitMode: 'duration' | 'segments' | 'silence'
  segmentDuration?: number // 秒
  segmentCount?: number
  silenceThreshold?: number // dB
  minSilenceDuration?: number // 秒
  outputFormat: string
  outputQuality: string
  filenamePrefix: string
  addTimestamp: boolean
}

interface SplitResult {
  name: string
  path: string
  duration: number
  size: number
}

// 获取音频时长（秒）- 使用 ffmpeg 直接获取
async function getAudioDuration(filePath: string): Promise<number> {
  return new Promise((resolve, reject) => {
    // 尝试使用 ffprobe 路径
    const ffprobePath = FFMPEG_PATH.replace('ffmpeg', 'ffprobe').replace('ffmpeg.exe', 'ffprobe.exe')
    
    const ffprobeArgs = [
      '-v', 'error',
      '-show_entries', 'format=duration',
      '-of', 'default=noprint_wrappers=1:nokey=1',
      filePath
    ]
    
    // 先尝试使用 ffprobe
    const ffprobe = spawn(ffprobePath, ffprobeArgs)
    let output = ''
    
    ffprobe.stdout.on('data', (data) => {
      output += data.toString()
    })
    
    ffprobe.on('close', (code) => {
      if (code === 0) {
        const duration = parseFloat(output.trim())
        if (!isNaN(duration) && duration > 0) {
          resolve(duration)
        } else {
          // 如果 ffprobe 失败，使用 ffmpeg 的 -i 参数来获取时长
          getDurationWithFFmpeg(filePath).then(resolve).catch(reject)
        }
      } else {
        // ffprobe 失败，使用 ffmpeg
        getDurationWithFFmpeg(filePath).then(resolve).catch(reject)
      }
    })
    
    ffprobe.on('error', () => {
      // ffprobe 不存在，使用 ffmpeg
      getDurationWithFFmpeg(filePath).then(resolve).catch(reject)
    })
  })
}

// 使用 ffmpeg 获取时长（备用方案）
function getDurationWithFFmpeg(filePath: string): Promise<number> {
  return new Promise((resolve, reject) => {
    const ffmpegArgs = [
      '-i', filePath,
      '-f', 'null',
      '-'
    ]
    
    const ffmpeg = spawn(FFMPEG_PATH, ffmpegArgs)
    let errorOutput = ''
    
    ffmpeg.stderr.on('data', (data) => {
      errorOutput += data.toString()
      // 从错误输出中解析时长（ffmpeg 会在 stderr 中输出时长信息）
      const durationMatch = errorOutput.match(/Duration: (\d{2}):(\d{2}):(\d{2})\.(\d{2})/)
      if (durationMatch) {
        const hours = parseInt(durationMatch[1])
        const minutes = parseInt(durationMatch[2])
        const seconds = parseInt(durationMatch[3])
        const centiseconds = parseInt(durationMatch[4])
        const totalSeconds = hours * 3600 + minutes * 60 + seconds + centiseconds / 100
        resolve(totalSeconds)
      }
    })
    
    ffmpeg.on('close', (code) => {
      // 即使失败，也尝试从输出中解析
      const durationMatch = errorOutput.match(/Duration: (\d{2}):(\d{2}):(\d{2})\.(\d{2})/)
      if (durationMatch) {
        const hours = parseInt(durationMatch[1])
        const minutes = parseInt(durationMatch[2])
        const seconds = parseInt(durationMatch[3])
        const centiseconds = parseInt(durationMatch[4])
        const totalSeconds = hours * 3600 + minutes * 60 + seconds + centiseconds / 100
        resolve(totalSeconds)
      } else {
        reject(new Error('无法获取音频时长'))
      }
    })
    
    ffmpeg.on('error', (err) => {
      reject(err)
    })
  })
}

// 获取音质对应的比特率
function getBitrate(quality: string): string {
  const qualityMap: Record<string, string> = {
    low: '64k',
    medium: '128k',
    high: '192k',
    veryhigh: '320k'
  }
  return qualityMap[quality] || '192k'
}

// 生成输出文件名
function generateOutputFilename(
  prefix: string,
  index: number,
  total: number,
  format: string,
  addTimestamp: boolean
): string {
  const paddedIndex = String(index).padStart(String(total).length, '0')
  let filename = `${prefix}_${paddedIndex}`
  
  if (addTimestamp) {
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5)
    filename = `${prefix}_${timestamp}_${paddedIndex}`
  }
  
  return `${filename}.${format}`
}

// 按时长分割
async function splitByDuration(
  config: SplitAudioConfig,
  duration: number,
  sendProgress: (progress: number) => void
): Promise<SplitResult[]> {
  const results: SplitResult[] = []
  const segmentDuration = config.segmentDuration || 300
  const totalSegments = Math.ceil(duration / segmentDuration)
  
  for (let i = 0; i < totalSegments; i++) {
    const startTime = i * segmentDuration
    const endTime = Math.min(startTime + segmentDuration, duration)
    const actualDuration = endTime - startTime
    
    if (actualDuration <= 0) break
    
    const outputFilename = generateOutputFilename(
      config.filenamePrefix,
      i + 1,
      totalSegments,
      config.outputFormat,
      config.addTimestamp
    )
    const outputPath = path.join(config.outputFolder, outputFilename)
    
    await new Promise<void>((resolve, reject) => {
      const ffmpegArgs = [
        '-i', config.inputPath,
        '-ss', startTime.toString(),
        '-t', actualDuration.toString(),
        '-c:a', config.outputFormat === 'mp3' ? 'libmp3lame' : 
               config.outputFormat === 'wav' ? 'pcm_s16le' :
               config.outputFormat === 'm4a' ? 'aac' :
               config.outputFormat === 'aac' ? 'aac' :
               config.outputFormat === 'ogg' ? 'libvorbis' : 'libmp3lame',
        '-b:a', getBitrate(config.outputQuality),
        '-y', // 覆盖已存在的文件
        outputPath
      ]
      
      const ffmpeg = spawn(FFMPEG_PATH, ffmpegArgs)
      let errorOutput = ''
      
      ffmpeg.stderr.on('data', (data) => {
        errorOutput += data.toString()
      })
      
      ffmpeg.on('close', (code) => {
        if (code === 0) {
          // 获取输出文件信息
          const stats = fs.statSync(outputPath)
          results.push({
            name: outputFilename,
            path: outputPath,
            duration: actualDuration,
            size: stats.size
          })
          
          sendProgress(Math.round(((i + 1) / totalSegments) * 100))
          resolve()
        } else {
          reject(new Error(`FFmpeg 分割失败 (退出代码: ${code})`))
        }
      })
      
      ffmpeg.on('error', (err) => {
        reject(err)
      })
    })
  }
  
  return results
}

// 按段数分割
async function splitBySegments(
  config: SplitAudioConfig,
  duration: number,
  sendProgress: (progress: number) => void
): Promise<SplitResult[]> {
  const results: SplitResult[] = []
  const segmentCount = config.segmentCount || 10
  const segmentDuration = duration / segmentCount
  
  for (let i = 0; i < segmentCount; i++) {
    const startTime = i * segmentDuration
    const endTime = Math.min(startTime + segmentDuration, duration)
    const actualDuration = endTime - startTime
    
    if (actualDuration <= 0) break
    
    const outputFilename = generateOutputFilename(
      config.filenamePrefix,
      i + 1,
      segmentCount,
      config.outputFormat,
      config.addTimestamp
    )
    const outputPath = path.join(config.outputFolder, outputFilename)
    
    await new Promise<void>((resolve, reject) => {
      const ffmpegArgs = [
        '-i', config.inputPath,
        '-ss', startTime.toString(),
        '-t', actualDuration.toString(),
        '-c:a', config.outputFormat === 'mp3' ? 'libmp3lame' : 
               config.outputFormat === 'wav' ? 'pcm_s16le' :
               config.outputFormat === 'm4a' ? 'aac' :
               config.outputFormat === 'aac' ? 'aac' :
               config.outputFormat === 'ogg' ? 'libvorbis' : 'libmp3lame',
        '-b:a', getBitrate(config.outputQuality),
        '-y',
        outputPath
      ]
      
      const ffmpeg = spawn(FFMPEG_PATH, ffmpegArgs)
      let errorOutput = ''
      
      ffmpeg.stderr.on('data', (data) => {
        errorOutput += data.toString()
      })
      
      ffmpeg.on('close', (code) => {
        if (code === 0) {
          const stats = fs.statSync(outputPath)
          results.push({
            name: outputFilename,
            path: outputPath,
            duration: actualDuration,
            size: stats.size
          })
          
          sendProgress(Math.round(((i + 1) / segmentCount) * 100))
          resolve()
        } else {
          reject(new Error(`FFmpeg 分割失败 (退出代码: ${code})`))
        }
      })
      
      ffmpeg.on('error', (err) => {
        reject(err)
      })
    })
  }
  
  return results
}

// 静音检测分割
async function splitBySilence(
  config: SplitAudioConfig,
  duration: number,
  sendProgress: (progress: number) => void
): Promise<SplitResult[]> {
  const results: SplitResult[] = []
  const threshold = config.silenceThreshold || -30
  const minDuration = config.minSilenceDuration || 1
  
  // 使用 silencedetect 滤镜检测静音点
  const silencePoints: number[] = [0] // 从0开始
  
  await new Promise<void>((resolve, reject) => {
    const ffmpegArgs = [
      '-i', config.inputPath,
      '-af', `silencedetect=noise=${threshold}dB:d=${minDuration}`,
      '-f', 'null',
      '-'
    ]
    
    const ffmpeg = spawn(FFMPEG_PATH, ffmpegArgs)
    let output = ''
    
    ffmpeg.stderr.on('data', (data) => {
      output += data.toString()
      // 解析 silencedetect 输出
      const lines = output.split('\n')
      for (const line of lines) {
        // silencedetect 输出格式: silence_start: 10.5 或 silence_end: 20.3
        const startMatch = line.match(/silence_start:\s*([\d.]+)/)
        const endMatch = line.match(/silence_end:\s*([\d.]+)/)
        
        if (startMatch) {
          const time = parseFloat(startMatch[1])
          if (!silencePoints.includes(time)) {
            silencePoints.push(time)
          }
        }
        if (endMatch) {
          const time = parseFloat(endMatch[1])
          if (!silencePoints.includes(time)) {
            silencePoints.push(time)
          }
        }
      }
    })
    
    ffmpeg.on('close', (code) => {
      if (code === 0 || code === 1) { // FFmpeg 可能返回1但仍然成功
        silencePoints.push(duration) // 添加结束点
        silencePoints.sort((a, b) => a - b)
        resolve()
      } else {
        reject(new Error(`FFmpeg 静音检测失败 (退出代码: ${code})`))
      }
    })
    
    ffmpeg.on('error', (err) => {
      reject(err)
    })
  })
  
  // 根据静音点分割音频
  const totalSegments = silencePoints.length - 1
  
  for (let i = 0; i < silencePoints.length - 1; i++) {
    const startTime = silencePoints[i]
    const endTime = silencePoints[i + 1]
    const actualDuration = endTime - startTime
    
    if (actualDuration <= 0.1) continue // 跳过太短的片段
    
    const outputFilename = generateOutputFilename(
      config.filenamePrefix,
      i + 1,
      totalSegments,
      config.outputFormat,
      config.addTimestamp
    )
    const outputPath = path.join(config.outputFolder, outputFilename)
    
    await new Promise<void>((resolve, reject) => {
      const ffmpegArgs = [
        '-i', config.inputPath,
        '-ss', startTime.toString(),
        '-t', actualDuration.toString(),
        '-c:a', config.outputFormat === 'mp3' ? 'libmp3lame' : 
               config.outputFormat === 'wav' ? 'pcm_s16le' :
               config.outputFormat === 'm4a' ? 'aac' :
               config.outputFormat === 'aac' ? 'aac' :
               config.outputFormat === 'ogg' ? 'libvorbis' : 'libmp3lame',
        '-b:a', getBitrate(config.outputQuality),
        '-y',
        outputPath
      ]
      
      const ffmpeg = spawn(FFMPEG_PATH, ffmpegArgs)
      let errorOutput = ''
      
      ffmpeg.stderr.on('data', (data) => {
        errorOutput += data.toString()
      })
      
      ffmpeg.on('close', (code) => {
        if (code === 0) {
          const stats = fs.statSync(outputPath)
          results.push({
            name: outputFilename,
            path: outputPath,
            duration: actualDuration,
            size: stats.size
          })
          
          sendProgress(Math.round(((i + 1) / totalSegments) * 100))
          resolve()
        } else {
          reject(new Error(`FFmpeg 分割失败 (退出代码: ${code})`))
        }
      })
      
      ffmpeg.on('error', (err) => {
        reject(err)
      })
    })
  }
  
  return results
}

export function setupAudioIpcHandlers() {
  // 获取音频文件信息
  ipcMain.handle(
    IPC_CHANNELS.audio.getFileInfo,
    async (_event, filePath: string) => {
      try {
        // 检查文件是否存在
        if (!fs.existsSync(filePath)) {
          return {
            success: false,
            error: '文件不存在'
          }
        }

        // 获取文件状态
        const stats = fs.statSync(filePath)
        
        return {
          success: true,
          size: stats.size,
          path: filePath
        }
      } catch (error) {
        console.error('获取文件信息失败:', error)
        return {
          success: false,
          error: error instanceof Error ? error.message : '未知错误'
        }
      }
    }
  )

  // 音频分割功能
  ipcMain.handle(
    IPC_CHANNELS.audio.splitAudio,
    async (event, config: SplitAudioConfig) => {
      try {
        // 验证输入文件
        if (!fs.existsSync(config.inputPath)) {
          return {
            success: false,
            error: '输入文件不存在'
          }
        }
        
        // 验证输出文件夹
        if (!fs.existsSync(config.outputFolder)) {
          fs.mkdirSync(config.outputFolder, { recursive: true })
        }
        
        // 获取音频时长
        const duration = await getAudioDuration(config.inputPath)
        if (duration <= 0) {
          return {
            success: false,
            error: '无法获取音频时长'
          }
        }
        
        // 发送进度更新的函数
        const sendProgress = (progress: number) => {
          const window = BrowserWindow.fromWebContents(event.sender)
          if (window) {
            window.webContents.send(IPC_CHANNELS.audio.splitProgress, progress)
          }
        }
        
        // 根据分割模式执行分割
        let results: SplitResult[]
        
        switch (config.splitMode) {
          case 'duration':
            results = await splitByDuration(config, duration, sendProgress)
            break
          case 'segments':
            results = await splitBySegments(config, duration, sendProgress)
            break
          case 'silence':
            results = await splitBySilence(config, duration, sendProgress)
            break
          default:
            return {
              success: false,
              error: '未知的分割模式'
            }
        }
        
        return {
          success: true,
          results: results,
          message: `成功分割为 ${results.length} 个片段`
        }
      } catch (error) {
        console.error('音频分割失败:', error)
        return {
          success: false,
          error: error instanceof Error ? error.message : '未知错误'
        }
      }
    }
  )
}

